/**
 * 在 Webpack 中，Tree Shaking 是一种优化技术，旨在消除未使用的代码，从而减小最终打包文件的体积，提高应用的性能。
  1. 什么是 Tree Shaking？
  Tree Shaking 是一种通过静态分析代码来识别和删除未使用的模块或代码块的技术。它的目标是确保最终打包的代码只包含实际使用的部分，避免冗余代码的存在。

  2. Tree Shaking 的工作原理
  Tree Shaking 主要依赖于 ES6 模块（即 `import` 和 `export`）的静态结构。与 CommonJS 模块不同，ES6 模块在编译时能够确定哪些导出是被使用的，从而可以安全地移除未使用的导出。

  3. 配置 Tree Shaking
  在 Webpack 中，启用 Tree Shaking 主要依赖于以下几个步骤：

  1. 使用 ES6 模块
  确保代码中使用 ES6 的模块语法（`import` 和 `export`），因为 Tree Shaking 只支持这种语法。

  示例：
  ```javascript
  // module.js
  export const usedFunction = () => {
      console.log('This function is used');
  };

  export const unusedFunction = () => {
      console.log('This function is not used');
  };

  // main.js
  import { usedFunction } from './module';

  usedFunction(); // 只会保留这个函数
  ```

  2. 设置生产模式
  在 Webpack 的配置文件中，将模式设置为 `production`。在生产模式下，Webpack 会自动启用许多优化功能，包括 Tree Shaking。

  ```javascript
  module.exports = {
      mode: 'production',
      // 其他配置...
  };
  ```

  3. 配置 `sideEffects`
  在项目的 `package.json` 中，可以通过 `sideEffects` 字段来指定哪些文件是有副作用的。默认情况下，Webpack 会假设所有文件都是无副作用的，因此如果某些文件确实有副作用（例如，修改全局状态），需要明确标记。

  ```json
  {
      "sideEffects": [
          "*.css", // 指定 CSS 文件有副作用
          "*.js"   // 如果某些 JS 文件有副作用，可以列出
      ]
  }
  ```

  4. 注意事项
  - 模块化: Tree Shaking 依赖于模块的静态结构，因此使用 ES6 模块是非常重要的。
  - 副作用: 确保正确配置 `sideEffects`，以防止移除必要的代码。
  - 测试: 在启用 Tree Shaking 后，进行充分的测试以确保应用的功能没有受到影响。

  总结
  Tree Shaking 是 Webpack 中一种强大的优化技术，通过消除未使用的代码，可以显著减小打包文件的体积，提高应用的性能。通过使用 ES6 模块、设置生产模式和正确配置 `sideEffects`，开发者可以有效利用 Tree Shaking 功能，优化项目的构建输出。希望这个总结对你理解 Webpack 中的 Tree Shaking 有所帮助！
 */
const path = require("path");
const glob = require("glob");
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CSSMinimizerPlugin = require("css-minimizer-webpack-plugin");
const { PurgeCSSPlugin } = require("purgecss-webpack-plugin");

console.log(
  glob.sync(`${path.resolve(__dirname, "../src")}/**/*`, { nodir: true })
);

module.exports = {
  mode: "production",
  optimization: {
    chunkIds: "deterministic", // 生成文件名时使用确定的文件名
    runtimeChunk: {
      name: "runtime", // 将runtime相关的代码单独打包
    },
    splitChunks: {
      // 分包配置
      chunks: "all", // 对所有模块都进行分割
      minSize: 10, // 分割的模块最小为10kb
      // 自己对需要进行拆包的内容进行分包
      cacheGroups: {
        utils: {
          test: /utils/,
          filename: "js/[id]_utils.js",
        },
        vendors: {
          // /node_modules/
          // window上面 /\
          // mac上面 /
          test: /[\\/]node_modules[\\/]/,
          filename: "js/[id]_vendors.js",
        },
      },
    },
    minimize: true, // 是否使用压缩
    // 压缩配置
    minimizer: [
      // JS压缩的插件: TerserPlugin
      new TerserPlugin({
        extractComments: false, // 不将注释提取到单独的文件中
        terserOptions: {
          compress: {
            arguments: true, // 移除console.log
            unused: true, // 移除未使用的代码
          },
          mangle: true, // 压缩变量名
          // toplevel: true, // 移除未使用的变量
          keep_fnames: true, // 保留函数名
        },
      }),
      // CSS压缩的插件: CSSMinimizerPlugin
      new CSSMinimizerPlugin({
        // parallel: true, // 开启多进程
      }),
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name].css",
      chunkFilename: "css/[name]_chunk.css",
    }),
    // 对css进行treeshaking
    new PurgeCSSPlugin({
      paths: glob.sync(`${path.resolve(__dirname, "../src")}/**/*`, {
        nodir: true, // 不包括文件夹
      }),
      // safelist表示: 哪些类名不能被移除
      safelist: function () {
        return {
          standard: ["body"],
        };
      },
    }),
  ],
};
